As RIAs (Rich Internet Applications) gain in popularity, it becomes easier for programmers to accidentally create security holes in their application. If you’re used writing server-side code, it can be easy to forget that any code running on the client (compiled or not) can ultimately be seen by prying eyes. And if you come from the desktop world, you might not be familiar with all the ins and outs of securely talking to services in the cloud. Unfortunately, there are no good tools (that I’m aware of) to help audit your apps to make sure you’re doing things right. Until then, here’s a quick crash course in RIA security for any app that needs to restrict calls to web services. Maybe you only want paying customers to use your app. Maybe you need to store personal information about each user in a database. Either way, you’ll need users to login and you’ll need to authenticate calls from the client to your web services.
The scenario:
- The user logs into the client (the RIA) and the client passes that username and password up to the server via a call to a web service.
- The server then validates that login and sends back a reply of success to the client.
- The client then permits the user to start froliking around in the application.
- Eventually, the client needs to talk to the server again to save or request some data (maybe this happens immediately after login to retrieve the data they saved during their last session).
The problem:
How do we make sure that the client calling the web service actually successfully logged in earlier? From the server’s point of view, you CANNOT assume that just because the client can only call this service if the login was successful, that this is actually what’s happening. Hackers can easily spoof your client and therefore fool the server.
All the hacker needs is the URL of the service which they can then easily type it into a browser to find the service’s entire API. To get this URL they can either decompile your code using tools like SilverlightSpy or Reflector (if you’re writing in .NET), or they can just use Fiddler to monitor the calls to your server.
- Obfuscating your code won’t help. Obfuscation might encrypt the service urls in your code but they will be decrypted by the time they show up in a tool like Fiddler.
- HTTPS/SSL won’t solve this either. HTTPS won’t do anything but encrypt the calls going over the internet. From the client and therefore from a tool like Fiddler, the URLs themselves will all be visibile.
- Passing up a hardcoded password with each request won’t solve this either. If you pass up a password, that means you need to store that password in your code somewhere. Even with obfuscation, hackers can still find it by decompiling your app and altering it in a very minor way to so it shows your hardcoded password in a message box at runtime.
The solution:
You must keep track of the user’s login (of some form of it) and pass that up with each sensative request to the server. The server then needs to validate that login each time before performing the requested operation.
The simple way:
Keep track of the username and password in a local variable and pass them up to the server with each request. This is relatively straight-forward, but has drawbacks:
- Using this approach makes it impossible to safely login from a webpage outside your RIA or support a “remember me” feature because it will invarably result in the user’s password being stored somewhere on the hard drive. Even if encryped this is still vulnerable to hackers. For more info, see my other article on Posting login credentials to your Silverlight app where I go over the concerns.
- Hackers can catch a packet being sent over the internet and resend that packet up to the server to get back a valid response. How would the server know the difference?
The bad way:
You could pass up a non-guessable user ID with each request (a GUID for example or a random ID that is unique to each user). Unfortunately, this has the same drawbacks as passing up a username and password. Additionally, user IDs are not necessarily private; your application may need to include that ID in a URL that could accidentally be pasted into an eamil by an unknowing user. Or, you application might need to expose a user’s ID to other users. Imagine that your application had a feature where users could see a list of other users that they could collaborate with. The client would get a list of these users and their IDs, the user would choose one or more, and the IDs would be sent back up to the server to notify it of the selection. As programmers, we need to assume that any data passed down to the client is ultimately hackable and therefore viewable by that client… therefore completely exposing each of those other users’ credentials. The bottom line: user IDs are not good surrogates for login credentials.
The best way:
Use session IDs (aka tokens) as an alternate to using real data like the username and password or a user ID. Once the user logs in, create a random string or GUID (this is your token), associate that token with the username and password (or better yet, associate it with their user ID if they have one) by storing these associations somewhere only your web service can access (most likely in memory or in a database). Your service can then pass that token back to the client upon a successful login. From that point forward, the client can use that token instead of a username and password everytime it wants to talk to the server. The server just needs to look up that token each time to find out the identity of the user, and the mere fact that the token was found indicates that the user making the request had logged in successful. Note: you should also make sure that the token expires eventually, otherwise, the token becomes just as useful to a hacker as the username and password.
Finally, how to accomplish this:
Method #1, the DIY (do it yourself) approach. As explained above, create a database or in-memory dictionary to hold the tokens for all the currently logged in users and add an extra parameter for the token to each web service method. Check out my previous article: Posting login credentials to your Silverlight app, where I demonstrate how to do this in a Silverlight client and an WCF web service. You can also download the source code from here.
Method #2, the session approach. In Part 2 of this article (RIA security 102: Using ASP.NET session state to authenticate web service calls) I demonstrate how to use built in ASP.NET session state objects to manage tokens for us. Note: There are other 3rd party options out there to do this for you too if you don’t use ASP.NET.
Method #3: If you though it couldn’t get any easier for us ASP.NET developers, there’s a third approach to use the Forms Authentication application service built into ASP.NET. Special thanks to John Papa for coming across this and Tim Huer for creating the only Silverlight example I’ve seen to date on using this library. This approach uses the System.Web.ApplicationServices.AuthenticationService namespace to manage and preserve a user’s login status between calls by passing back and forth an encrypted cookie. The encrypted cookie (or ticket as it is called) contains your username and login expiration. Each time the user makes a request to a method in your service that needs to be protected, you can use HttpContext.Current.User.Identity to determine if the user has been validated and what their username is. This approach works great once you get it configured and shifts some of the details to ASP.NET. Check out the source code here to see this technique in action from both the client and server’s perspective.
If you check out the source code for all 3 approaches, you’ll notice that they are identical from the end user’s perspective. Yet each uses the different approach mentioned above. Have fun comparing to see which works better for you.
[…] 29, 2008 by Tim Greenfield In part 1 (RIA security 101: Logins, web services, usernames and passwords), I discuss the importance of security in RIAs (Rich Internet Applications) and set the ground […]
Interesting post. Security is often an afterthought especially since so many are new to RIA. If you use IIS with ASP.NET another option is to use Forms Authentication. The Silverlight client can log in to the Forms Auth provider, passing the credentials once at login. The Forms Auth provider sends back an acknowledgement and is then set up for any repeat visits by the same user. When server calls are made, code can be written server side to intercept all calls and first make sure the user is indeed authenticated. This technique builds on Forms Auth and removes the need to create your own token technique.
[…] was reading a post by Tim Greenfield today regarding RIA and security. Taking this from the Silverlight RIA perspective this has some interesting turns. His scenarios […]
[…] was reading a post by Tim Greenfield today regarding RIA and security. He also followed this up with a nice post on how to implement one of his techniques using […]
Thanks for the addition John, I’ve added a note to this posting about this third option for ASP.NET users as well as some source code to demonstrate how to use it.
That’s awesome Tim! I’ve used this myself and its a very nice feature. I am probably going to discuss it in an upcoming MSDN Mag Data Points article.
I have switched to using Asp.Net login form (instead of Silverlight form), which stores user in Asp.Net session and redirects user to Silverlight Application web page (which is accessible only by already authenticated user). I guess that it is also safe enough approach.
In this way, login information can be preserved even on Cltr + F5 (full browser refresh).
Does the same method works, when I want to access ADO.net data services from within SL2?
I.e. can I use the HttpContext.Current.User.Identity in ADO.net ds, or I have to send the auth. cookie explicitly to ADO.net ds in webrequest header?
[…] been completely lost if I hadn’t stumbled upon Tim Greenfield’s blog, specifically this postwhich outlined the core ideas for implementing a secure login system that uses RIA services. After […]
using web service i want to login form for asp.net
Hello, after reading this remarkable piece of writing i am too cheerful to share my know-how here
with mates.
After this, there is a need to do is find some free software downloads along with their codes available on the Internet through your device. The process of jailbreaking your device will often include installation of, or the option to modify the interface of incoming calls so users can continue to use their handset while it is phoning.
I don’t even know how I ended up here, but I thought this post was great.
I don’t know who you are but definitely you are going to a famous blogger if
you are not already 😉 Cheers!
Here are the potential skin care benefits of the ingredient.
Wet work is specifically defined in the United Kingdom by the Health &
Safety Executive. In Nashville this means wear a hat, cover up and find
a good sunscreen.
Hey! This is kind of off topic but I need some advice from an established blog.
Is it difficult to set up your own blog? I’m not very techincal but I can figure things out
pretty fast. I’m thinking about setting up my own but
I’m not sure where to start. Do you have any tips or suggestions?
Thank you
You should take part in a contest for one of the most useful blogs
on the web. I most certainly will recommend this blog!
Some categories are anal, armature, lesbian, gay, shemale, BBW, etc.
Instead, you hang around, having sex with him, waiting for him to figure out
that he can’t live without you. But still there are many people in the society, who gets
from their daily boring routine and want to have some fun in their
life.
Greate post. Keep writing such kind of info on your site.
Im really impressed by it.
Hi there, You’ve performed a fantastic job. I’ll certainly digg it and personally recommend to
my friends. I am sure they will be benefited from this site.
Im use new gmail account
Im use new gmail account.thank u